“别把我跟你混为一谈,我努力过,所以我不后悔。”
写在前面
分享一些Ansible
中Playbook
执行顺序控制的手段以及运行选定的任务的笔记
不知道小伙伴们有么有遇到这样的情况
一些运维场景,Github
中找了很棒的剧本或者角色,但是只需要其中的一部分
一般情况下只能重新编辑(注释或者删掉)剧本处理,往往需要多次调整剧本,很麻烦
亦或是一个有角色的剧本,你希望先执行任务,在执行角色(默认角色总是先执行)
亦或是某些剧本你希望脱离编写顺序执行,自定义执行顺序
亦或是你希望同时通知多个handler
,处理程序被通知后立即执行,而不是等role、tasks
执行完统一执行等等
上面的问题都有解决办法,但是Ansible
本身提供了很多更优的解决方法,通过博文内容一起来学习下,涉及内容:
通过标记tags
仅运行标有特定标签的任务,或者从特定的任务开始执行Playbook
通过include_role && import_role
作为任,控制角色执行顺序
通过pre_task || post_task
控制任务执行前后的回调处理
通过listen
来监听多个handlers
通过meta: flush_handlers
立即运行通知的handlers
食用方式
了解Ansible
基础知识
可以编写 Ansible Playbook
、role
了解role
构成,剧本常见指令(语法)
理解不足小伙伴帮忙指正
博文使用的ansibler
版本
1 2 3 4 5 6 7 8 $ansible --versionansible 2.8.0rc1 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/student/.ansible/plugins/modules' , '/usr/share/ansible/plugins/modules' ] ansible python module location = /usr/lib/python3.6/site-packages/ansible executable location = /usr/bin/ansible python version = 3.6.8 (default, Apr 3 2019, 17:26:03) [GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] $
如果我会发光,就不必害怕黑暗。——王小波
对 Ansible 剧本资源打标签 在处理大型或复杂的剧本时,如果只希望运行部分剧本或部分任务
。可以将标签
应用于可能要跳过或运行的特定资源。
通过标签来标记资源
,在资源上使用tags关键字
,然后是要应用的标记列表。在Ansible
中tags
标记可用于下列资源:
每个任务
,这是使用标签的最常见方式之一。
整个剧本
,在剧本级别使用标签指令。
标记include_tasks
任务。include_tasks
加载的所有任务都与此标签关联。
角色
,角色中的所有任务都与此标签关联。
任务块
,块中的所有任务都与此标签关联。
看一个Demo,上面的标记依次来看体验下。在这之前,先准备一个角色,角色做一个echo的动作,
1 2 3 4 5 6 7 8 9 $ansible -galaxy init tag_role --init-path=roles- tag_role was created successfully $ansible -galaxy list | grep tag- tag_role, (unknown version) $cat roles/tag_role/tasks/main.yml--- - name: tags roles shell: echo 'tasks for tag_role'
编写一个剧本,在不同剧本资源执行块打上标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 --- - name: tags Demo 1 hosts: servera tags: - play-tag-1 roles: - role: tag_role tags: - role-tags tasks: - name: task 1 tag shell: echo 'tags to task 1' tags: - task-tags-1 - name: include or import a tasks file include_tasks: file: tasks_file tags: - include-import - block: - name: task 1 in block shell: echo 'task 1 in block' - name: task 2 in block shell: echo 'task 2 in block' tags: - block-tags - name: tags Demo 2 hosts: servera tags: - play-tag-2 tasks: - name: task 2 tag shell: echo 'tags to task 2' tags: - task-tag-2
执行上面编写剧本,默认情况下打了标签,如果没有显示的指令或者设置特殊的标签,剧本默认依旧按照没打标签的顺序执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ansible -playbook tags.yamlPLAY [tags Demo 1] ************************************************************************************ TASK [Gathering Facts] ******************************************************************************** ok: [servera] TASK [tag_role : tags roles] ************************************************************************** changed: [servera] TASK [task 1 tag] ************************************************************************************* changed: [servera] TASK [include or import a tasks file] **************************************************************** included: /home/student/DO447/labs/task-execution/tasks_file for servera TASK [task 1] ***************************************************************************************** changed: [servera] TASK [task 2] ***************************************************************************************** changed: [servera] TASK [task 1 in block] ******************************************************************************** changed: [servera] TASK [task 2 in block] ******************************************************************************** changed: [servera] PLAY [tags Demo 2] ************************************************************************************ TASK [Gathering Facts] ******************************************************************************** ok: [servera] TASK [task 2 tag] ************************************************************************************* changed: [servera] PLAY RECAP ******************************************************************************************** servera : ok=10 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
下面来看下如何管理标记资源,选择执行剧本资源
管理标记的资源 要列出 Playbook 中的所有标记,使用--list-tags
选项
1 2 3 4 5 6 7 8 9 10 $ansible -playbook tags.yaml --list-tagsplaybook: tags.yaml play TASK TAGS: [block-tags, include-import, play-tag-1, role-tags, task-tags-1] play TASK TAGS: [play-tag-2, task-tag-2] $
可以看到,上面的剧本的标签构成:
剧本tags Demo 1
包含标签TASK TAGS: [block-tags, include-import, play-tag-1, role-tags, task-tags-1]
剧本tags Demo 2
包含标签play-tag-2, task-tag-2
当希望运行特定的剧本资源时,给对应的资源标记打标签,然后使用ansible-playbook
运行playbook
时,添加--tags
选项来筛选 playbook 仅运行带有特定标签的play 或任务
。
1 2 3 4 5 6 7 8 9 $ansible -playbook tags.yaml --tags=play-tag-2PLAY [tags Demo 1] ************************************************************************************************* PLAY [tags Demo 2] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] TASK [task 2 tag] ************************************************************************************************** changed: [servera] PLAY RECAP ********************************************************************************************************* servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
运行指令里添加了 --tags=play-tag-2
,即只运行剧本tags Demo 2
,当需要运行多个标签时,之间逗号隔开
1 2 3 4 5 6 7 8 9 10 11 12 $ansible -playbook tags.yaml --tags=block-tags,role-tagsPLAY [tags Demo 1] ************************************************************************************************* TASK [tag_role : tags roles] *************************************************************************************** changed: [servera] TASK [task 1 in block] ********************************************************************************************* changed: [servera] TASK [task 2 in block] ********************************************************************************************* changed: [servera] PLAY [tags Demo 2] ************************************************************************************************* PLAY RECAP ********************************************************************************************************* servera : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
当希望运行大多数剧本资源,个别剧本资源不运行,可以在运行ansible-playbook
命令时,使用--skip-tags
选项跳过带有特定标签的任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ansible -playbook tags.yaml --list-tagsplaybook: tags.yaml play TASK TAGS: [block-tags, include-import, play-tag-1, role-tags, task-tags-1] play TASK TAGS: [play-tag-2, task-tag-2] $ansible -playbook tags.yaml --skip-tags play-tag-1PLAY [tags Demo 1] ************************************************************************************************* PLAY [tags Demo 2] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] TASK [task 2 tag] ************************************************************************************************** changed: [servera] PLAY RECAP ********************************************************************************************************* servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
特殊的标签 如果有些剧本资源,你希望它始终运行,或是希望它始终不运行,即使在你使用tags、skip-tags
指定标签的情况下,Ansible 这两种场景中提供了特殊标记:
always
:带有 always 标记的资源始终都会运行,除非明确指定--skip-tags always
选项。
never
:带有 never 特殊标记的资源不会运行,除非明确指定--tags never
选项。
看一个Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $cat tags-all.yaml --- - name: tags Demo 1 hosts: servera tags: - play-tag-1 - never roles: - role: tag_role tags: - role-tags tasks: - name: task 1 tag shell: echo 'tags to task 1' tags: - task-tags-1 - name: include or import a tasks file include_tasks: file: tasks_file tags: - include-import - block: - name: task 1 in block shell: echo 'task 1 in block' - name: task 2 in block shell: echo 'task 2 in block' tags: - block-tags - name: tags Demo 2 hosts: servera tags: - always tasks: - name: task 2 tag shell: echo 'tags to task 2'
可以看到剧本1设置never
标签,所以默认总不会执行,剧本2设置always
,所以默认总会执行
1 2 3 4 5 6 7 8 9 10 $ansible -playbook tags-all.yamlPLAY [tags Demo 1] ************************************************************************************************* PLAY [tags Demo 2] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] TASK [task 2 tag] ************************************************************************************************** changed: [servera] PLAY RECAP ********************************************************************************************************* servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
执行输出可以看到,剧本1没有执行,剧本2默认执行,这里,可能有小伙伴会说,如果我希望打标签的资源全部执行或者全部不执行,但是我的标签太多了,都写上很麻烦,况且我还有一些没有打标签的任务,我应该如何处理,Ansible
在这些场景中提供了一些指令参数。
命令行指定标签时的特定参数:
tagged
标记将运行任何带有显式标记的资源
untagged
标记将运行不带有显式标记的资源
all
参数将包括 Play 中的所有任务,无论是否带有标记,这是默认行为。
在来看看 Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 $cat tags-all.yaml --- - name: tags Demo 1 hosts: servera tags: - play-tag-1 roles: - role: tag_role tags: - role-tags tasks: - name: task 1 tag shell: echo 'tags to task 1' tags: - task-tags-1 - name: include or import a tasks file include_tasks: file: tasks_file tags: - include-import - block: - name: task 1 in block shell: echo 'task 1 in block' - name: task 2 in block shell: echo 'task 2 in block' tags: - block-tags - name: tags Demo 2 hosts: servera tasks: - name: task 2 tag shell: echo 'tags to task 2'
tagged 标记
将运行任何带有显式标记的资源,会发现,剧本 tags Demo 2
的task 2 tag
任务没有标签,所以没有执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ansible -playbook tags-all.yaml --tags=taggedPLAY [tags Demo 1] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] TASK [tag_role : tags roles] *************************************************************************************** changed: [servera] TASK [task 1 tag] ************************************************************************************************** changed: [servera] TASK [include or import a tasks file] ***************************************************************************** included: /home/student/DO447/labs/task-execution/tasks_file for servera TASK [task 1] ****************************************************************************************************** changed: [servera] TASK [task 2] ****************************************************************************************************** changed: [servera] TASK [task 1 in block] ********************************************************************************************* changed: [servera] TASK [task 2 in block] ********************************************************************************************* changed: [servera] PLAY [tags Demo 2] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] PLAY RECAP ********************************************************************************************************* servera : ok=9 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
untagged 标记
将运行不带有显式标记的资源,会发现只有剧本 tags Demo 2
的task 2 tag
任务执行了,因为他没有标签
1 2 3 4 5 6 7 8 9 10 $ansible -playbook tags-all.yaml --tags=untaggedPLAY [tags Demo 1] ************************************************************************************************* PLAY [tags Demo 2] ************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************* ok: [servera] TASK [task 2 tag] ************************************************************************************************** changed: [servera] PLAY RECAP ********************************************************************************************************* servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
控制任务执行 角色最先执行 在Playbook
中,Ansible
始终先执行角色中的任务,然后执行在tasks
部分下定义的任务,来看一个Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $cat deploy_apache_demo.yml --- - name: Ensure Apache is deployed hosts: all gather_facts: no tasks: - name: Open the firewall firewalld: service: http permanent: yes state: enabled roles: - role: apache
上面的执行,可以看到执行数据顺序为,先执行firewall
角色,然后执行apache
角色,最后执行的是 Open the firewall
,
1 2 3 4 5 6 7 8 9 10 11 12 13 PLAY [Ensure Apache is deployed] ********************************************************************* ..... TASK [firewall : Ensure Firewall Sources Configuration] ********************************************** ..... TASK [apache : Ensure httpd packages are installed] ************************************************** ..... TASK [apache : Ensure SELinux allows httpd connections to a remote database] ************************* ..... TASK [apache : Ensure httpd service is started and enabled] ****************************************** ..... TASK [Open the firewall] ***************************************************************************** ..... PLAY RECAP *******************************************************************************************
剧本里没有定义firewall,为什么会执行,是因为apache角色依赖了他,可以在apache角色的meta目录的maia.ymal 文件下面看到,它依赖了firewall角色
1 2 3 4 5 6 $cat roles/apache/meta/main.yml | grep -C 2 firewalldependencies: - name: firewall $
所以不管剧本编写顺序如何,同一剧本中执行顺序为,依赖角色要在当前角色之前执行,当前角色role要在调用剧本任务task之前执行。
为了剧本的可读性,一般情况下,剧本任务是写在角色后面的,整个书写顺序也就是执行顺序。
那么,如果希望在角色执行前执行任务,应该如何处理,有两种方法
其一是使用task钩子,类似生命周期中的回调函数一样,
另一钟方法,即下面提到的,使用import或者include
,关于这两个动作,小伙伴们一定不陌生,前端常见的模板引擎一般都会涉及到。不同的动作,实相同的功能,但是原理是不同的
import 或 include 作为任务的角色 Ansible的最新版本允许将角色作为任务来包含或导入
,而不是使用play中的角色部分
。通过这样的方式,可以使剧本按照编写的顺序执行,而不是先执行角色的方式
。
优点是可以按照编写顺序运行一组任务、导入或包含一个角色,然后运行更多的任务。
缺点是,在没有仔细检查的情况下,可能不太清楚您的剧本使用的是哪些角色,因为角色切入了任务内部
import和include 有些许区别
使用include_role
模块可以动态
包含角色,
使用import_role
模块则可静态
导入角色。
创建一个角色,执行的任务为打印当前的主机名
1 2 3 $ansible -galaxy init role_tasks_demo$echo "- shell: hostname" > roles/role_tasks_demo/tasks/main.yml
编写剧本,两种不同的方式引入角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 --- - name: Executing a role as a task hosts: a_web_servers tasks: - name: A normal task debug: msg: 'first task' - name: A task to import_role role_tasks_demo here import_role: name: role_tasks_demo - name: A task to include role_tasks_demo here include_role: name: role_tasks_demo - name: Another normal task debug: msg: 'second task'
执行剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ansible -playbook role_tasks.yamlPLAY [Executing a role as a task] ******************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [serverb.lab.example.com] TASK [A normal task] ********************************************************************************* ok: [serverb.lab.example.com] => { "msg" : "first task" } TASK [role_tasks_demo : shell] *********************************************************************** changed: [serverb.lab.example.com] TASK [A task to include role_tasks_demo here] ****************************************************** TASK [role_tasks_demo : shell] *********************************************************************** changed: [serverb.lab.example.com] TASK [Another normal task] *************************************************************************** ok: [serverb.lab.example.com] => { "msg" : "second task" } PLAY RECAP ******************************************************************************************* serverb.lab.example.com : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到,按照任务编写的顺序执行,角色执行了两次,这里需要注意一点,通过 import_role
方式导入的角色并会作为当前剧本的一部分,而通过 include
的方式会作为一个单独的任务模块来执行,我么通过执行的输出也可以看到,具体的原因:
使用import_role
时,ansible-playbook
命令首先解析角色并插入到play
中,然后开始执行。Ansible
会立即检测和报告语法错误,不会开始执行playbook。
使用 include_role
时,Ansible 会在 play 执行期间到达 include_role 任务时解析角色并插⼊到 play 中。如果Ansible 检测到角色中存在语法错误,则中止执行 playbook 。
对于 when 指令
的行为有所不同。使用include_role
任务时,如果when
指令中的条件为 false,则 Ansible不解析角色。看一个Demno
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $cat role_tasks.yaml --- - name: Executing a role as a task hosts: servera tasks: - name: A normal task debug: msg: 'first task' - name: import_role role import_role: name: role_tasks_demo when: false - name: include_role role include_role: name: role_tasks_demo - name: Another normal task debug: msg: 'second task'
执行我么可以看到。import_role
被直接跳过了,因为when的原因,并没有执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ansible -playbook role_tasks.yamlPLAY [Executing a role as a task] ********************************************************************* TASK [Gathering Facts] ******************************************************************************** ok: [servera] TASK [A normal task] ********************************************************************************** ok: [servera] => { "msg" : "first task" } TASK [role_tasks_demo : shell] ************************************************************************ skipping: [servera] TASK [include_role role] ****************************************************************************** TASK [role_tasks_demo : shell] ************************************************************************ changed: [servera] TASK [Another normal task] **************************************************************************** ok: [servera] => { "msg" : "second task" } PLAY RECAP ******************************************************************************************** servera : ok=4 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
角色执行前&&任务执行后的钩子 有时候希望⼀个剧本 在角色之前运行某些任务
,以及它们所通知的处理程序。也可能希望在普通任务tasks
和处理程序handler
运行后运行 play 中的任务
。
可以使用两个指令
(而非 tasks
)来实现这一目标:
pre_tasks
是在 roles 部分前
运行的 tasks 部分
。
post_tasks
是在 tasks 部分
以及 tasks 所通知的任何处理程序后
运行的 tasks 部分
。
通过Demo来看下,创建一个测试角色,同样打印主机名
1 2 $ansible -galaxy init tasks_hook_demo$echo "- shell: hostname" > roles/tasks_hook_demo/tasks/main.yml
编写剧本,使用 pro_taks
和post_task
来执行剧本之前前后的钩子任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 --- - name: task task exec order hosts: a_web_servers pre_tasks: - name: pre_tasks in task shell: echo 'pre_tasks' post_tasks: - name: post_tasks in taks shell: echo 'post_tasks' tasks: - name: task shell: echo 'tasks' roles: - tasks_hook_demo
可以看到编写顺序并不会影响到执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ansible -playbook tasks_hook.yamlPLAY [task task exec order] ************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [serverb.lab.example.com] TASK [pre_tasks in task] ***************************************************************************** changed: [serverb.lab.example.com] TASK [tasks_hook_demo : shell] *********************************************************************** changed: [serverb.lab.example.com] TASK [task] ****************************************************************************************** changed: [serverb.lab.example.com] TASK [post_tasks in taks] **************************************************************************** changed: [serverb.lab.example.com] PLAY RECAP ******************************************************************************************* serverb.lab.example.com : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
上面的执行顺序为 pre_tasks > roles > tasks > post_tasks
,不管语句顺序如何变化,都不会改变执行顺序
这里,有小伙伴会想到,如果任务中有handlers
应该如何处理?
有handlers
的执行顺序 Ansible 按照以下顺序运行 Play 的不同部分:
pre_tasks
pre_tasks
部分中通知的处理程序 handlers
roles
tasks
roles
和 tasks
部分中通知的处理程序 handlers
post_tasks
post_tasks
部分中通知的处理程序 handlers
这些部分在 Play 中的编写顺序不会修改以上列出的执行顺序。来看一个demo
这里先创建一个角色,使用shell 模块打印一句话
1 2 3 4 5 6 7 8 9 10 11 12 $ansible -galaxy init task_liruilong_exec_order --init-path=roles- task_liruilong_exec_order was created successfully $ansible -galaxy list | grep liruilo- task_liruilong_exec_order, (unknown version) $tee roles/task_liruilong_exec_order/tasks/main.yml <<- EOF > --- > - name: role: task_liruilong_exec_order > shell: echo "roles liruilong" > EOF --- - name: role task_liruilong_exec_order shell: echo "roles liruilong"
然后我在角色中添加一个通知,在角色的handlers文件夹中定义执行的事件,在taks发生chagent的时候会触发通知,执行通知的handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $vim roles/task_liruilong_exec_order/tasks/main.yml$cat roles/task_liruilong_exec_order/tasks/main.yml--- - name: role task_liruilong_exec_order shell: echo "roles liruilong" notify: - role_handler $vim roles/task_liruilong_exec_order/handlers/main.yml$cat roles/task_liruilong_exec_order/handlers/main.yml--- - name: role_handler shell: echo 'role in role_handler' $vim task_order.yaml
来看下的剧本,在pre_tasks和post_tasks,tasks中,都有剧本中handler的notify。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $cat task_order.yaml --- - name: tesk task exec order hosts: servera pre_tasks: - name: task in pre_taks shell: echo 'task in pre_tasks' notify: - ploybook_in_handler roles: - role: task_liruilong_exec_order tasks: - name: task in tasks shell: echo 'task in tasks' notify: - ploybook_in_handler post_tasks: - name: taks in post_tasks shell: echo 'task in post_tasks' notify: - ploybook_in_handler handlers: - name: ploybook_in_handler shell: echo ' ploybook in handle'
执行剧本,可以看到剧本你的执行顺序为:pre_taks > pre_taks handler > role > tasks > role handler > tasks handler > post_tasks > post_tasks handler
1 2 3 4 5 6 7 8 9 10 11 12 $ansible -playbook task_order.yamlPLAY [tesk task exec order] ************************************************************************** TASK [Gathering Facts] *******************************************************************************ok: [servera] TASK [task in pre_taks] ******************************************************************************changed: [servera] RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera] TASK [task_liruilong_exec_order : role task_liruilong_exec_order] ***********************************changed: [servera] TASK [task in tasks] *********************************************************************************changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler] *******************************************changed: [servera] RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera] TASK [taks in post_tasks] ****************************************************************************changed: [servera] RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera] PLAY RECAP *******************************************************************************************servera : ok=9 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这里要说明的是剧本中这些块的顺序不会改变执行顺序。一个剧本包含pre_tasks,roles,tasks,post tasks和handlers部分是不寻常的。如果在多个部分中得到通知,则处理程序handler可以在剧本执行期间的不同时间多次运行。但是不会存在 一个处理的程序连续执行多次,即同一时间段,多此次通知只执行一次。
那么这里的话,如果希望某一任务在发生change后,同时通知多个处理程序handler,应该如何处理
任务一次性通知多个handlers任务
按名称通知handlers列表。
通知配置了listen来监听多个handlers
下面的剧本中,notify部分并没有发生改变,但是handlers
部分添加一个listen
属性,即由原来的通知变成了监听
,这里其实有点类似观察者设计模式的两种实现方式,当观察者的数据较少的时候,采用的是推的一种方式,较多时,通过拉的方式实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 --- - name: tesk task exec order hosts: servera pre_tasks: - name: task in pre_taks shell: echo 'task in pre_tasks' notify: - ploybook_in_handler roles: - role: task_liruilong_exec_order tasks: - name: task in tasks shell: echo 'task in tasks' notify: - ploybook_in_handler post_tasks: - name: taks in post_tasks shell: echo 'task in post_tasks' notify: - ploybook_in_handler handlers: - name: ploybook_in_handler 1 shell: echo ' ploybook in handle 1' listen: ploybook_in_handler - name: ploybook_in_handler 2 shell: echo ' ploybook in handle 2' listen: ploybook_in_handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 $ansible -playbook task_order.yamlPLAY [tesk task exec order] *************************************************************************** TASK [Gathering Facts] ******************************************************************************** ok: [servera] TASK [task in pre_taks] ******************************************************************************* changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] *************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] *************************************************************** changed: [servera] TASK [task_liruilong_exec_order : role task_liruilong_exec_order] ************************************ changed: [servera] TASK [task in tasks] ********************************************************************************** changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler] ******************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] *************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] *************************************************************** changed: [servera] TASK [taks in post_tasks] ***************************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] *************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] *************************************************************** changed: [servera] PLAY RECAP ******************************************************************************************** servera : ok=12 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
当然,有小伙伴说,我不嫌麻烦,我就想每次推,那么应该如何实现,可以在notafy写成一个list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $cat roles/task_liruilong_exec_order/tasks/main.yml--- - name: role task_liruilong_exec_order shell: echo "roles liruilong" notify: - role_handler1 - role_handler2 $cat roles/task_liruilong_exec_order/handlers/main.yml--- - name: role_handler1 shell: echo 'role in role_handler 1' - name: role_handler2 shell: echo 'role in role_handler 2' $
这样也是可以的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ansible -playbook task_order.yamlPLAY [tesk task exec order] *************************************************************************** TASK [Gathering Facts] ******************************************************************************** ok: [servera] ......... TASK [task_liruilong_exec_order : role task_liruilong_exec_order] ************************************ changed: [servera] TASK [task in tasks] ********************************************************************************** changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler1] ******************************************* changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler2] ******************************************* changed: [servera] .....
在上面的Demo中,可以看到,任务处理程序 handler 总是在一个任务块处理完之后才会执行,那如果我希望在任务执行到一半,执行前面的任务处理程序,应该这么处理?
立即运行剧本中特定任务通知的任何处理程序 若要立即运行由 Play 中特定任务通知的任何处理程序,可以添加一个使用 meta 模块
及 flush_handlers 参数
任务:
meta: flush_handlers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 --- - name: tesk task exec order hosts: servera pre_tasks: - name: task in pre_taks shell: echo 'task in pre_tasks' notify: - ploybook_in_handler roles: - role: task_liruilong_exec_order tasks: - name: task in tasks 1 shell: echo 'task in tasks 1' notify: - ploybook_in_handler - meta: flush_handlers - name: task in tasks 2 shell: echo 'task in tasks 2' notify: - ploybook_in_handler post_tasks: - name: taks in post_tasks shell: echo 'task in post_tasks' notify: - ploybook_in_handler handlers: - name: ploybook_in_handler 1 shell: echo ' ploybook in handle 1' listen: ploybook_in_handler - name: ploybook_in_handler 2 shell: echo ' ploybook in handle 2' listen: ploybook_in_handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 $ ansible-playbook task_order.yaml PLAY [tesk task exec order] ************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [servera] TASK [task in pre_taks] ****************************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] ************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] ************************************************************** changed: [servera] TASK [task_liruilong_exec_order : role task_liruilong_exec_order] *********************************** changed: [servera] TASK [task in tasks 1] ******************************************************************************* changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler1] ****************************************** changed: [servera] RUNNING HANDLER [task_liruilong_exec_order : role_handler2] ****************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] ************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] ************************************************************** changed: [servera] TASK [task in tasks 2] ******************************************************************************* changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] ************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] ************************************************************** changed: [servera] TASK [taks in post_tasks] **************************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 1] ************************************************************** changed: [servera] RUNNING HANDLER [ploybook_in_handler 2] ************************************************************** changed: [servera] PLAY RECAP ******************************************************************************************* servera : ok=16 changed=15 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
控制主机执行顺序 Ansible根据剧本hosts指令确定要管理的主机。默认情况下,Ansible2.4和更高版本根据清单中主机列出的顺序运行剧本
。您可以使用order指令
更改该顺序。
order指令接受以下值:
inventory
清单顺序。这是默认值。
reverse_inventory
清单相反顺序。
sorted
主机按字母顺序排列。数字在字母前排序。
reverse_sorted
主机以相反的字母顺序排列。
shuffle
每次您执行剧本时,随机排序。
由于Ansible通常在多个主机上并行运行每个任务,因此 ansible-playbook 命令的输出可能无法反映预期的顺序:输出显示的是任务完成顺序,而不是执行顺序。
来看一个Demo,下面的配置中,定义了order: sorted
的顺序执行主机
1 2 3 4 5 6 7 8 9 $ cat host-all.yaml --- - name: Executing a role as a task hosts: all order: sorted tasks: - name: A normal task debug: msg: 'first task'
可以看到执行顺序即为字母顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $ ansible-playbook host-all.yaml -f 1 PLAY [Executing a role as a task] ********************************************************************* TASK [Gathering Facts] ******************************************************************************** ok: [servera] ok: [serverb] ok: [serverc] ok: [serverd] ok: [servere] ok: [serverf] TASK [A normal task] ********************************************************************************** ok: [servera] => { "msg" : "first task" } ok: [serverb] => { "msg" : "first task" } ok: [serverc] => { "msg" : "first task" } ok: [serverd] => { "msg" : "first task" } ok: [servere] => { "msg" : "first task" } ok: [serverf] => { "msg" : "first task" } PLAY RECAP ******************************************************************************************** servera : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverb : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverc : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverd : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 servere : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverf : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
主机执行顺序为随机执行
1 2 3 4 5 6 7 8 9 10 $ cat host-all.yaml --- - name: Executing a role as a task hosts: all order: shuffle tasks: - name: A normal task debug: msg: 'first task'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $ ansible-playbook host-all.yaml -f 1 PLAY [Executing a role as a task] ********************************************************************* TASK [Gathering Facts] ******************************************************************************** ok: [serverb] ok: [serverc] ok: [servere] ok: [serverf] ok: [serverd] ok: [servera] TASK [A normal task] ********************************************************************************** ok: [serverf] => { "msg" : "first task" } ok: [servera] => { "msg" : "first task" } ok: [servere] => { "msg" : "first task" } ok: [serverd] => { "msg" : "first task" } ok: [serverb] => { "msg" : "first task" } ok: [serverc] => { "msg" : "first task" } PLAY RECAP ******************************************************************************************** servera : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverb : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverc : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverd : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 servere : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 serverf : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
来看一个具体的实际应用。
实战 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 $ cat deploy_haproxy.yml - name: Ensure HAProxy is deployed hosts: lb_servers force_handlers: True pre_tasks: - name: Setting the maintenance message copy: dest: /etc/motd.d/maintenance content: "Maintenance in progress\n" roles: - role: haproxy post_tasks: - name: Removing the maintenance message file: path: /etc/motd.d/maintenance state: absent handlers: - name: Sending an email to student mail: subject: "HAProxy reloaded on {{ inventory_hostname }} " to: student@workstation.lab.example.com delegate_to: localhost become: false listen: reload haproxy - name: Logging a message to syslog syslogger: msg: "HAProxy reloaded on {{ inventory_hostname }} " delegate_to: localhost become: false listen: reload haproxy
上面的剧本在执行haproxy这个角色的时候,通过pro_taks
添加登录时的欢迎信息,提示系统正在维护,维护信息写到 /etc/motd.d/maintenance
,同时在角色执行完后,在post_tasks
中删除欢迎信息。
同时监听角色中的haproxy services文件重新加载的事件,当服务配置文件重新load的时候,发送邮件,并且写入系统日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ cat roles/haproxy/handlers/main.yml --- - name: restart haproxy service: name: haproxy state: restarted - name: reload haproxy service: name: haproxy state: reloaded $
执行剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 $ ansible-playbook deploy_haproxy.yml PLAY [Ensure HAProxy is deployed] ********************************************************************* TASK [Gathering Facts] ******************************************************************************** ok: [servera.lab.example.com] TASK [Setting the maintenance message] **************************************************************** changed: [servera.lab.example.com] TASK [firewall : Ensure Firewall Sources Configuration] *********************************************** ok: [servera.lab.example.com] => (item={'port' : '80/tcp' }) TASK [haproxy : Ensure haproxy packages are present] ************************************************** changed: [servera.lab.example.com] TASK [haproxy : Ensure haproxy is started and enabled] ************************************************ changed: [servera.lab.example.com] TASK [haproxy : Ensure haproxy configuration is set ] ************************************************** changed: [servera.lab.example.com] RUNNING HANDLER [haproxy : reload haproxy] ************************************************************ changed: [servera.lab.example.com] RUNNING HANDLER [Sending an email to student] ********************************************************* ok: [servera.lab.example.com] RUNNING HANDLER [Logging a message to syslog] ********************************************************* changed: [servera.lab.example.com] TASK [Removing the maintenance message] *************************************************************** changed: [servera.lab.example.com] PLAY RECAP ******************************************************************************************** servera.lab.example.com : ok=10 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 You have new mail in /var/spool/mail/student
登录机器可以发现系统维护的信息,等角色执行完。维护信息消失
1 2 3 4 5 6 7 8 9 10 11 12 13 $ ssh servera Activate the web console with: systemctl enable --now cockpit.socket Maintenance in progress [student@servera ~]$ exit logout Connection to servera closed. You have mail in /var/spool/mail/student $ ssh servera Activate the web console with: systemctl enable --now cockpit.socket Last login: Sat Aug 13 01:15:44 2022 from 172.25.250.9 [student@servera ~]$
可以看到邮件信息
1 2 3 4 5 6 $ mail Heirloom Mail version 12.5 7/5/10. Type ? for help . "/var/spool/mail/student" : 1 message 1 new>N 1 root@workstation.lab Sat Aug 13 01:10 27/1102 "HAProxy reloaded on servera.lab.example.com" & q Held 1 message in /var/spool/mail/student
博文参考 《Red Hat Ansible Engine 2.8 DO447》